#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <stdio.h>

#include "main.h"

#include "Fifo.h"
//#include <malloc.h>
#include <string.h>

static uint8_t *Begin;
static uint8_t *End;
static uint8_t *PtrWr;
static uint8_t *PtrRd;
static uint32_t m_CNDTR;
static uint32_t *pCNDTR;

void Fifo_Init_uart(void *buf, int size)
{
	//NeedFree = 0;
	Begin = (uint8_t *)buf;
	End = Begin + size;
	PtrWr = Begin;
	PtrRd = Begin;
	m_CNDTR = size;
	pCNDTR = &m_CNDTR;
}

int Fifo_size_uart(void)
{
	return End - Begin;
}

int Fifo_length_uart(void)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	uint32_t len;
	if (rd <= wr)
	{
		len = wr - rd;
	}
	else
	{
		len = (End - Begin) - (rd - wr);
	}
	return len;
}

int Fifo_free_length_uart(void)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	uint32_t len;
	if (rd <= wr)
	{
		len = wr - rd;
	}
	else
	{
		len = (End - Begin) - (rd - wr);
	}
	return (End - Begin) - 1 - len;
}

int Fifo_get_read_block_length_uart(void)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	uint32_t len;
	if (rd <= wr)
	{
		len = wr - rd;
	}
	else
	{
		len = End - rd;
	}
	return len;
}

void Fifo_flush_uart(void)
{
	uint8_t *wr = End - *(pCNDTR);
	PtrRd = wr;
}

bool Fifo_putch_uart(uint8_t ch)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	if (wr + 1 == rd)
		return false;
	if (wr == End && rd == Begin)
		return false;
	*PtrWr = ch;
	PtrWr++;
	if (PtrWr >= End)
		PtrWr = Begin;
	m_CNDTR = End - PtrWr;
	return true;
}

bool Fifo_getch_uart(uint8_t *ch)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	if (rd == wr)
		return false;
	*ch = *rd;
	rd++;
	if (rd >= End)
		rd = Begin;
	PtrRd = rd;
	return true;
}

int Fifo_read_uart(void *buf, int max_len)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	int len;
	if (rd <= wr)
	{
		len = wr - rd;
	}
	else
	{
		len = (End - Begin) - (rd - wr);
	}
	if (len)
	{
		if (len > max_len)
			len = max_len;
		uint8_t *rd1 = rd + len;
		if (rd1 < End)
		{
			memcpy(buf, rd, len);
			PtrRd = rd1;
		}
		else
		{
			rd1 = rd1 - (End - Begin);
			memcpy((uint8_t *)buf, rd, End - rd);
			memcpy((uint8_t *)buf + (End - rd), Begin, rd1 - Begin);
			PtrRd = rd1;
		}
	}
	return len;
}

bool Fifo_write_uart(const void *buf, int size)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	uint32_t len, freelen;
	if (rd <= wr)
	{
		len = wr - rd;
	}
	else
	{
		len = (End - Begin) - (rd - wr);
	}
	freelen = (End - Begin) - 1 - len;
	if (freelen < (uint32_t)size)
		return false;

	uint8_t *wr1 = wr + size;
	if (wr1 < End)
	{
		memcpy(wr, buf, size);
		PtrWr = wr1;
	}
	else
	{
		wr1 = wr1 - (End - Begin);
		memcpy(wr, (uint8_t *)buf, End - wr);
		memcpy(Begin, (uint8_t *)buf + (End - wr), wr1 - Begin);
		PtrWr = wr1;
	}
	m_CNDTR = End - PtrWr;
	return true;
}

bool Fifo_peek_uart(void *buf, int size)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	int len;
	if (rd <= wr)
	{
		len = wr - rd;
	}
	else
	{
		len = (End - Begin) - (rd - wr);
	}
	if (len < size)
		return false;
	if (len)
	{
		if (len > size)
			len = size;
		uint8_t *rd1 = rd + len;
		if (rd1 < End)
		{
			memcpy(buf, rd, len);
			// fifo->PtrRd = rd1;
		}
		else
		{
			rd1 = rd1 - (End - Begin);
			memcpy((uint8_t *)buf, rd, End - rd);
			memcpy((uint8_t *)buf + (End - rd), Begin, rd1 - Begin);
			// fifo->PtrRd = rd1;
		}
	}
	return true;
}

uint8_t *Fifo_peekc_uart(uint8_t *ch)
{
	uint8_t *wr = End - *(pCNDTR);
	uint8_t *rd = PtrRd;
	if (rd == wr)
		return NULL;
	*ch = *rd;
	return rd;
}
